/**
 * @fileoverview search 插件
 */

function Search (vm) {
  /**
   * @description 关键词搜索
   * @param {regexp|string} key 要搜索的关键词
   * @param {boolean} anchor 是否将搜索结果设置为锚点
   * @param {string} style 搜索结果的样式
   */
  vm.search = function (key, anchor, style = '') {
    const obj = {}
    const stack = []
    const res = [];

    // 遍历搜索
    (function traversal (nodes, path) {
      for (let i = 0; i < nodes.length; i++) {
        const node = nodes[i]
        if (node.type === 'text' && key) {
          const arr = node.text.split(key)
          const children = []
          if (arr.length > 1) {
            // 找到关键词
            for (let j = 0; j < arr.length; j++) {
              if (arr[j]) {
                children.push({
                  type: 'text',
                  text: arr[j]
                })
              }
              if (j !== arr.length - 1) {
                // 关键词转为一个 span
                res.push(`${path}[${i}].children[${children.length}].attrs.style`)
                children.push({
                  name: 'span',
                  attrs: {
                    id: anchor ? 'search' + res.length : undefined, // 用于锚点的 id
                    class: `content-red`,
                    style
                  },
                  children: [{
                    type: 'text',
                    text: key instanceof RegExp ? key.exec(node.text)[0] : key
                  }]
                })
              }
            }
            if (key instanceof RegExp) {
              key.exec(node.text)
            }
            if (anchor) {
              for (let l = stack.length; l--;) {
                // 给父组件做标记，将该标签暴露出来
                if (stack[l].c) {
                  break
                } else {
                  obj[stack[l].path] = 1
                }
              }
            }
            obj[`${path}[${i}]`] = {
              name: 'span',
              c: anchor ? 1 : undefined,
              s: 1,
              children
            }
          }
        } else if (node.s) {
          let text = ''
          // 复原上一次的结果
          for (let k = 0; k < node.children.length; k++) {
            const child = node.children[k]
            if (child.text) {
              text += child.text
            } else {
              text += child.children[0].text
            }
          }
          nodes[i] = {
            type: 'text',
            text
          }
          if (key && (key instanceof RegExp ? key.test(text) : text.includes(key))) {
            i--
          } else {
            obj[`${path}[${i}]`] = nodes[i]
          }
        } else if (node.children) {
          stack.push({
            path: `${path}[${i}].c`,
            c: node.c || node.name === 'table'
          })
          traversal(node.children, `${path}[${i}].children`)
          stack.pop()
        }
      }
    })(vm.data.nodes, 'nodes')

    return new Promise(function (resolve) {
      const findAllIndexes = (str, charToFind) => {
        let indexes = []
        let start = 0
        while ((str.indexOf(charToFind, start) !== -1)) {
          indexes.push(str.indexOf(charToFind, start))
          start = str.indexOf(charToFind, start) + 1
        }
        return indexes
      }
      const getValue = (object = {}, keys) => {
        keys = keys.replace(/\[['"]?(.*?)['"]?\]/g, '.$1')?.split('.');
        const checkValue = (obj, key) => {
          if (!key?.[0]) {
            return obj;
          }
          if (typeof obj[key[0]] === 'object') {
            return checkValue(obj[key[0]], key.slice(1));
          }
          if (key.length > 1) {
            return undefined;
          }
          return obj[key[0]];
        };
        return checkValue(object, keys);
      }
      const handleNode = (node, index) => {
        let number = 0
        node.children.map(item => {
          if (item.name && item.name === 'span') {
            number = number + 1
            if (number !== index) {
              item.attrs.class = ''
            }
          }
        })
        return node
      }
      vm.setData(obj, () => {
        let markIndex  = 1
        let oldMark = ''
        let resData = res.map((item, index) => {
          item = item.slice(0, -24)
          let node = JSON.parse(JSON.stringify(getValue(vm.data, item)))
          if (index === 0) {
            oldMark = item
          }
          if (index > 0 && item === oldMark) {
            markIndex = markIndex + 1
          }
          if (index > 0 && item !== oldMark) {
            oldMark = item
            markIndex = 1
          }
          node = handleNode(node, markIndex)
          return node
        })
        let res_list = res
        let res_list_match = []
        res_list.map((item, index) => {
          res_list_match[index] = findAllIndexes(item.slice(0, -11), '.')
          res_list_match[index].reverse()
        })
        res_list_match.map((item, index) => {
          let nodes = resData[index]
          item.map((chil, chilIndex) => {
            let node = JSON.parse(JSON.stringify(getValue(vm.data, res_list[index].slice(0, chil))))
            let temporary_node = nodes
            nodes = {
              name: node.name,
              attrs: {
                style: ''
              },
              children: [temporary_node]
            }
            if (node.attrs && node.attrs.style) {
              nodes.attrs.style = node.attrs.style
            }
          })
          resData[index] = nodes
        })
        resolve({
          nodes: res,
          res: resData,
          num: res.length, // 结果数量
          /**
           * @description 高亮某一个结果
           * @param {number} i 第几个
           * @param {string} hlstyle 高亮的样式
           */
          highlight (i, hlstyle = 'background-color:#FF9632') {
            if (i < 1 || i > res.length) return
            const obj = {}
            if (this.last) {
              obj[res[this.last - 1]] = style
            }
            this.last = i
            obj[res[i - 1]] = hlstyle
            vm.setData(obj)
          },
          /**
           * @description 跳转到搜索结果
           * @param {number} i 第几个
           * @param {number} offset 偏移量
           */
          jump: anchor
            ? (i, offset) => {
                if (i > 0 && i <= res.length) {
                  vm.navigateTo('search' + i, offset)
                }
              }
            : undefined
        })
      })
    })
  }
}

module.exports = Search
